package com.shxy.cloudclassroom.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shxy.cloudclassroom.entity.pojo.*;
import com.shxy.cloudclassroom.entity.vo.DownloadHistoryVO;
import com.shxy.cloudclassroom.entity.vo.ViewHistoryVO;
import com.shxy.cloudclassroom.entity.dto.UserDTO;
import com.shxy.cloudclassroom.exception.*;
import com.shxy.cloudclassroom.mapper.UserMapper;
import com.shxy.cloudclassroom.service.*;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

import static com.shxy.cloudclassroom.utils.SystemConstant.USER_CODE;

@Service
@Transactional
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {

    @Resource
    private UserMapper userDao;
    
    @Resource
    private MajorService majorService;
    @Resource
    private OssService ossService;
    // 用户登录
    public User login(UserDTO userDTO, HttpSession session) {
        //1.根据用户名查询用户
        String username = userDTO.getUsername();
        User user = userDao.selectOne(
                new QueryWrapper<User>().eq("username",username));

        //校验用户是否存在
        if (user == null) {
            throw new UserNotfoundException();
        }

        //2.取出session中的验证码
        String checkCode = (String) session.getAttribute(USER_CODE + username);
        //2.1校验验证码是否正确
        String code = userDTO.getCode();
        //验证码是否为空
        if (code == null || checkCode == null) {
            throw new NotfoundVerificationCodeException();
        }
        //忽略大小写
        if (!code.equalsIgnoreCase(checkCode)) {
            throw new VerificationCodeErrorException();
        }
        //3.比较密码
        String password = userDTO.getPassword();
        String passwordSecret = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));
        if (!user.getPassword().equals(passwordSecret))
            throw new PasswordErrorException();
        return user;
    }


    @Override
    // 更新管理员
    public void updateAdminById(Long userId) {
        userDao.updateAdminById(userId);
    }

    /**
     * 检查用户是否存在
     *
     * @param username
     * @return
     */
    // 检查用户是否存在
    public String checkUser(String username) {
        if (username == null || username.trim().isEmpty()) {
            return "";
        }
        User user = userDao.selectOne(new QueryWrapper<User>().eq("username", username));
        return user == null ? "" : username;
    }

    /**
     * 处理注册业务逻辑
     * @param user
     */
    // 用户注册
    public void register(UserDTO user) {
        // 校验参数
        if (user == null || user.getUsername() == null || user.getUsername().trim().isEmpty()) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        
        if (user.getPassword() == null || user.getPassword().trim().isEmpty()) {
            throw new IllegalArgumentException("密码不能为空");
        }
        
        //1.查询用户名是否重复
        User userDB = userDao.selectOne(new QueryWrapper<User>().eq("username", user.getUsername()));
        if (!ObjectUtils.isEmpty(userDB))
            //2.如果用户名已存在
            throw new UserNameAlreadyExistsException();
        //3.MD5对密码进行加密处理
        String newPassword = DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8));
        user.setPassword(newPassword);
        User inserUser = BeanUtil.copyProperties(user, User.class);
        userDao.insert(inserUser);
    }
    
    @Override
    // 更新用户信息
    public Map<String, Object> updateUser(User user, String oldPassword, HttpSession session) {
        Map<String, Object> result = new HashMap<>();
        try {
            User currentUser = (User) session.getAttribute("loginUser");

            // 确保只能更新当前用户的信息，使用session中的用户ID而不是前端传递的ID
            user.setId(currentUser.getId());

            // 如果提供了新密码，需要验证原密码
            if (user.getPassword() != null && !user.getPassword().isEmpty()) {
                if (oldPassword == null || oldPassword.isEmpty()) {
                    result.put("success", false);
                    result.put("message", "请输入原密码");
                    return result;
                }

                // 验证原密码是否正确
                String encryptedOldPassword = DigestUtils.md5DigestAsHex(oldPassword.getBytes(StandardCharsets.UTF_8));
                if (!currentUser.getPassword().equals(encryptedOldPassword)) {
                    result.put("success", false);
                    result.put("message", "原密码错误");
                    return result;
                }

                // 加密新密码
                String encryptedNewPassword = DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8));
                user.setPassword(encryptedNewPassword);
            } else {
                // 不更新密码字段
                user.setPassword(null);
            }

            // 更新用户信息
            this.updateById(user);

            // 更新session中的用户信息
            User updatedUser = this.getById(user.getId());
            session.setAttribute("loginUser", updatedUser);

            result.put("success", true);
            result.put("message", "用户信息更新成功");
        } catch (Exception e) {
            e.printStackTrace();
            result.put("success", false);
            result.put("message", "更新失败：" + e.getMessage());
        }
        return result;
    }
    
    @Override
    // 上传用户头像
    public String uploadAvatar(MultipartFile file) throws JsonProcessingException {
        String avatarUrl = null;
        avatarUrl = ossService.uploadAvatar(file);
        // 返回JSON格式的响应
        Map<String, String> response = new HashMap<>();
        response.put("url", avatarUrl);
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(response);
    }
    
    @Override
    // 发送验证码
    public String sendCode(String username, HttpSession httpSession) {
        String code = RandomUtil.randomString(6);
        log.debug("用户名:{}", username);
        System.out.println(username);
        httpSession.setAttribute(USER_CODE + username, code);
        httpSession.setMaxInactiveInterval(120);//有效期两分钟
        log.debug("验证码:{}", code);
        return code;
    }
    
    @Override
    // 获取浏览历史
    public List<ViewHistoryVO> getViewHistory(Long id, LearningResourceService learningResourceService,
                                             ViewHistoryService viewHistoryService, MajorService majorService) {
        LambdaQueryWrapper<ViewHistory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ViewHistory::getUserId, id);
        List<ViewHistory> viewHistories = viewHistoryService.list(wrapper);
        Map<Integer, String> majorNameMap = getResourcesByHistoryList(viewHistories, learningResourceService);
        
        // 创建资源映射
        List<Long> resourceIds = viewHistories.stream()
                .map(ViewHistory::getResourceId)
                .distinct()
                .toList();
        Map<Long, LearningResource> resourceMap = new HashMap<>();
        if (!resourceIds.isEmpty()) {
            List<LearningResource> resourceList = learningResourceService.list(
                    new LambdaQueryWrapper<LearningResource>()
                            .in(LearningResource::getId, resourceIds)
            );
            resourceMap = resourceList.stream()
                    .collect(Collectors.toMap(LearningResource::getId, resource -> resource));
        }
        
        List<ViewHistoryVO> historyVOS = new ArrayList<>();
        for (ViewHistory history : viewHistories) {
            LearningResource resource = resourceMap.get(history.getResourceId().intValue());
            if (resource != null) {
                ViewHistoryVO historyVO = new ViewHistoryVO();
                historyVO.setResourceId(resource.getId());
                historyVO.setResourceTitle(resource.getTitle());
                historyVO.setResourceType(resource.getResourceType());
                historyVO.setResourceDescription(resource.getDescription());
                historyVO.setType(resource.getType());
                historyVO.setViewTime(history.getViewTime());
                if (resource.getMajorId() != null) {
                    historyVO.setMajorName(majorNameMap.get(resource.getMajorId()));
                } else {
                    historyVO.setMajorName("未分类");
                }
                historyVOS.add(historyVO);
            }
        }
        return historyVOS;
    }
    
    @Override
    // 获取下载历史
    public List<DownloadHistoryVO> getDownloadHistory(Integer id, LearningResourceService learningResourceService,
                                                     DownloadHistoryService downloadHistoryService, MajorService majorService) {
        LambdaQueryWrapper<DownloadHistory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DownloadHistory::getUserId, id);
        List<DownloadHistory> downloadHistoryList = downloadHistoryService.list(wrapper);
        Map<Integer, String> majorNameMap = getResourcesByHistoryList(downloadHistoryList, learningResourceService);
        
        // 创建资源映射
        List<Long> resourceIds = downloadHistoryList.stream()
                .map(DownloadHistory::getResourceId)
                .distinct()
                .toList();
        Map<Long, LearningResource> resourceMap = new HashMap<>();
        if (!resourceIds.isEmpty()) {
            List<LearningResource> resourceList = learningResourceService.list(
                    new LambdaQueryWrapper<LearningResource>()
                            .in(LearningResource::getId, resourceIds)
            );
            resourceMap = resourceList.stream()
                    .collect(Collectors.toMap(LearningResource::getId, resource -> resource));
        }
        
        List<DownloadHistoryVO> historyVOS = new ArrayList<>();
        for (DownloadHistory history : downloadHistoryList) {
            LearningResource resource = resourceMap.get(history.getResourceId().intValue());
            if (resource != null) {
                DownloadHistoryVO historyVO = new DownloadHistoryVO();
                historyVO.setResourceId(resource.getId());
                historyVO.setResourceTitle(resource.getTitle());
                historyVO.setResourceType(resource.getResourceType());
                historyVO.setResourceDescription(resource.getDescription());
                historyVO.setType(resource.getType());
                historyVO.setUploadTime(history.getUploadTime());
                if (resource.getMajorId() != null) {
                    historyVO.setMajorName(majorNameMap.get(resource.getMajorId()));
                } else {
                    historyVO.setMajorName("未分类");
                }
                historyVOS.add(historyVO);
            }
        }
        return historyVOS;
    }
    
    @Override
    // 根据历史记录列表获取资源列表
    public Map<Integer, String> getResourcesByHistoryList(List<? extends History> historyList, LearningResourceService service) {
        List<Long> resourceIds = historyList.stream()
                .map(History::getResourceId)
                .distinct()
                .toList();
        List<LearningResource> resourceList = new ArrayList<>();
        if (!resourceIds.isEmpty()) {
            resourceList = service.list(
                    new LambdaQueryWrapper<LearningResource>()
                            .in(LearningResource::getId, resourceIds)
            );
        }
        Set<Integer> majorIds = resourceList.stream()
                .map(LearningResource::getMajorId)
                .collect(Collectors.toSet());
        Map<Integer, String> majorNameMap = new HashMap<>();
        if (!majorIds.isEmpty()) {
            List<Major> majors = majorService.list(
                    new LambdaQueryWrapper<Major>()
                            .in(Major::getId, majorIds)
            );
            majorNameMap = majors.stream()
                    .collect(Collectors.toMap(Major::getId, Major::getName));
        }

        return majorNameMap;
    }
}